﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Reflection;
using System.IO;

namespace Warehouse.Web.AppCode
{
    public class AuthorityCfg : ConfigurationSection
    {
        [ConfigurationProperty("items", IsDefaultCollection = false)]
        [ConfigurationCollection(typeof(AuthorityCollection),
            AddItemName = "item")]
        public AuthorityCollection Authorities
        {
            get
            {
                return (AuthorityCollection)base["items"];
            }
        }

        public string GetPermissionNameByAction(string page, string action)
        {
            if (page != null)
            {
                AuthorityItem authority = Authorities.GetByPage(page);
                if (authority != null)
                {
                    return authority.Actions.GetPmNameByAction(action);
                }
            }
            return string.Empty;
        }
    }

    public class AuthorityCollection : ConfigurationElementCollection
    {
        public AuthorityItem this[int index]
        {
            get { return (AuthorityItem)BaseGet(index); }
        }

        public void Add(AuthorityItem serviceConfig)
        {
            BaseAdd(serviceConfig);
        }

        public void Clear()
        {
            BaseClear();
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new AuthorityItem();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((AuthorityItem)element).Page;
        }

        public void Remove(AuthorityItem serviceConfig)
        {
            BaseRemove(serviceConfig.Page);
        }

        public void RemoveAt(int index)
        {
            BaseRemoveAt(index);
        }

        public void Remove(string name)
        {
            BaseRemove(name);
        }
        public AuthorityItem GetByPage(string page)
        {
            ConfigurationElement element = BaseGet(page);
            if (element == null)
            {
                return null;
            }
            else
            {
                return (AuthorityItem)element;
            }
        }
    }

    public class AuthorityItem : ConfigurationElement
    {
        [ConfigurationProperty("page", IsRequired = true, IsKey = true)]
        public string Page
        {
            get { return (string)this["page"]; }
        }

        [ConfigurationProperty("actions", IsDefaultCollection = false)]
        [ConfigurationCollection(typeof(ActionCollection),
            AddItemName = "action")]
        public ActionCollection Actions
        {
            get
            {
                return (ActionCollection)base["actions"];
            }
        }
    }

    public class ActionCollection : ConfigurationElementCollection
    {
        public Action this[int index]
        {
            get { return (Action)BaseGet(index); }
        }

        public void Add(Action serviceConfig)
        {
            BaseAdd(serviceConfig);
        }

        public void Clear()
        {
            BaseClear();
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new Action();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((Action)element).Name;
        }

        public void Remove(Action serviceConfig)
        {
            BaseRemove(serviceConfig.Name);
        }

        public void RemoveAt(int index)
        {
            BaseRemoveAt(index);
        }

        public void Remove(string name)
        {
            BaseRemove(name);
        }
        public string GetPmNameByAction(string action)
        {
            ConfigurationElement element = BaseGet(action);
            if (element == null)
            {
                return "";
            }
            else
            {
                return ((Action)element).PmName;
            }
        }
    }

    public class Action : ConfigurationElement
    {
        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return (string)this["name"]; }
        }
        [ConfigurationProperty("pmName", IsRequired = true)]
        public string PmName
        {
            get { return (string)this["pmName"]; }
        }
    }

    public class Authority
    {
        //数据库中获取权限列表
        private static Dictionary<string, int> GetPmDics()
        {
            Dictionary<string, int> pmDics = HttpRuntime.Cache["PmDics"] as Dictionary<string, int>;
            if (pmDics != null)
            {
                return pmDics;
            }

            pmDics = Warehouse.DataAccess.Permission.GetPermissionDic();
            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["PmDicsExpiration_Hour"]))
            {
                HttpRuntime.Cache.Insert("PmDics", pmDics, null, DateTime.Now.AddHours(6), System.Web.Caching.Cache.NoSlidingExpiration);
            }
            else
            {
                HttpRuntime.Cache.Insert("PmDics", pmDics, null, DateTime.Now.AddHours(Convert.ToDouble(ConfigurationManager.AppSettings["PmDicsExpiration_Hour"])), System.Web.Caching.Cache.NoSlidingExpiration);
            }
            return pmDics;
        }

        //获取权限配置文件
        private static AuthorityCfg GetAuthorityCfg()
        {
            AuthorityCfg authorityCfg = HttpRuntime.Cache["AuthorityCfg"] as AuthorityCfg;
            if (authorityCfg != null)
            {
                return authorityCfg;
            }

            ExeConfigurationFileMap exeConfigMap = new ExeConfigurationFileMap();

            //exeConfigMap.ExeConfigFilename = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\Authority.config";
            exeConfigMap.ExeConfigFilename = HttpContext.Current.Server.MapPath("~/Authority.config");
            //exeConfigMap.ExeConfigFilename = @"F:\myfile\Warehouse\Code\Warehouse.Web\Authority.config";
            Configuration cfg = ConfigurationManager.OpenMappedExeConfiguration(exeConfigMap, ConfigurationUserLevel.None);
            ConfigurationSection authoritySection = cfg.GetSection("authority");
            if (authoritySection != null)
            {
                authorityCfg = (AuthorityCfg)authoritySection;
            }
            if (authorityCfg == null)
            {
                return null;
            }
            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["AuthorityCfgExpiration_Hour"]))
            {
                HttpRuntime.Cache.Insert("AuthorityCfg", authorityCfg, null, DateTime.Now.AddHours(6), System.Web.Caching.Cache.NoSlidingExpiration);
            }
            else
            {
                HttpRuntime.Cache.Insert("AuthorityCfg", authorityCfg, null, DateTime.Now.AddHours(Convert.ToDouble(ConfigurationManager.AppSettings["AuthorityCfgExpiration_Hour"])), System.Web.Caching.Cache.NoSlidingExpiration);
            }

            return authorityCfg;
        }

        /// <summary>
        /// 用户权限验证
        /// </summary>
        /// <param name="page">请求的页面，如 /Management/Authority.aspx</param>
        /// <param name="action">请求的操作，如AddDepartment</param>
        /// <param name="permissions">当前用户已经拥有的权限</param>
        /// <returns></returns>
        public static bool Validate(string page, string action, DataAccess.PermissionInUser[] permissions)
        {
            if (string.IsNullOrEmpty(action))
            {
                return false;
            }
            AuthorityCfg authorityCfg = GetAuthorityCfg();
            if (authorityCfg == null)
            {
                //如果没有配置文件，允许所有访问
                return true;
            }

            string askedPmName = authorityCfg.GetPermissionNameByAction(page, action);
            if (string.IsNullOrEmpty(askedPmName))
            {
                //如果请求的页面和action在配置文件中没有配置，允许访问
                return true;
            }
            Dictionary<string, int> pmDics = GetPmDics();
            int askedPmID = 0;
            if (pmDics.ContainsKey(askedPmName))
            {
                askedPmID = pmDics[askedPmName];
            }
            else
            {
                //如果配置文件中配置的权限操作在数据库中没有配置，允许访问
                return true;
            }

            if (permissions == null)
            {
                //不满足上述允许访问的情况且当前用户没有任何权限，不允许访问
                return false;
            }
            DataAccess.PermissionInUser p = permissions.Where(item => item.PermissionID == askedPmID).FirstOrDefault();
            if (p != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    public class AuthorityControl : System.Web.UI.Control
    {
        protected override void RenderChildren(System.Web.UI.HtmlTextWriter writer)
        {
            if (string.IsNullOrEmpty(this.Action) || this.Action.Split(new char[] { ',' }).Any(act => Authority.Validate(this.TargetPage, act, (DataAccess.PermissionInUser[])this.Page.Session["UserPermission"])))
            {
                base.RenderChildren(writer);
            }
        }

        public string Action
        {
            get;
            set;
        }

        private string _Page = null;
        public string TargetPage
        {
            get
            {
                if (!string.IsNullOrEmpty(_Page))
                {
                    return this.Page.Request.Url.AbsolutePath;
                }
                else
                {
                    return _Page;
                }
            }
            set
            {
                _Page = value;
            }
        }
    }
}